import json
import re

from django.http import JsonResponse
from django.views import View

from apps.users.models import User


"""
1、判断用户名是否存在
前端：当用户输入用户名，失去焦点，发送axios（ajax）请求
后端：
    请求：接受用户名
    业务逻辑：根据用户名查询数据库
        当查询结果数据为0时，表示未注册
        当查询结果数据为1时，表示已经被注册过
    响应：Json数据
        {code:0, count:0/1, errmsg:ok}
    路由：get usernames/<username>/count/
"""
class UsernameCountView(View):

    def get(self, request, username):
        # 接受用户名，对用户名进行长度判断
        # if not re.match('[a-zA-Z0-9_-]{5,20}', username):
        #     return JsonResponse({'code':200, 'errmsg':'用户名不满足需求'})

        # 根据用户名查询数据库
        count = User.objects.filter(username=username).count()
        return JsonResponse({'code':0, count:count, 'errmsg':'ok'})


"""
2、用户注册功能
前端：输入用户名，密码，确认密码，手机号，是否同意协议之后，点击注册按钮
     前端会发送axios（ajax）请求
后端：
    请求：接受请求，获取数据
    业务逻辑：验证数据，添加到数据库
    响应：Json数据
         响应状态码：0 成功，400 失败
    路由：post register/
"""
"""
如果需求是注册成功后即表示用户认证通过，那么此时可以在注册成功后实现状态保持（注册成功既已经登录）
如果需求是注册成功后不表示用户认证通过，那么此时不用在注册成功后实现状态保持（注册成功，单独登录）

实现状态保持的主要两种形式：
    1、在客户端存储用户信息，使用Cookie
    2、在服务端存储用户信息，使用Session
"""
class RegisterView(View):

    def post(self, request):
        # 1、接受请求(POST -> Json)
        body_bytes = request.body  # 获取Json数据
        body_str = body_bytes.decode()  # 转换bytes类型数据为字符串类型数据
        body_dict = json.loads(body_str)  # 转换字符串类型数据为字典类型数据

        # 2、获取数据
        username = body_dict.get('username')
        password = body_dict.get('password')
        password2 = body_dict.get('password2')
        mobile = body_dict.get('mobile')
        allow = body_dict.get('allow')

        # 3、验证数据：数据是否全部填写
        if not all([username, password, password2, mobile, allow]):
            return JsonResponse({"code":400, "errmsg":"数据不全"})
        # 验证数据-用户名是否符合规则
        if not re.match("[a-zA-Z0-9_-]{5,20}", username):
            return JsonResponse({"code":400, "errmsg":"用户名不符合规则"})
        # 验证数据-用户名是否重复
        if User.objects.filter(username=username).exists():
            return JsonResponse({"code": 400, "errmsg": "用户名已存在"})
        # 验证数据-密码是否符合规则
        if len(password) < 8 or len(password) > 20:
            return JsonResponse({"code": 400, "errmsg": "密码长度不对"})
        # 验证数据-两次密码是否一致
        if not password == password2:
            return JsonResponse({"code": 400, "errmsg": "两次密码不一致"})
        # 验证数据-手机号
        if not len(mobile) == 11:
            return JsonResponse({"code": 400, "errmsg": "手机号码有问题"})

        # 4、数据添加到数据库
        # User.objects.create(username=username, password=password, mobile=mobile)
        # user = User(username=username, password=password, mobile=mobile)
        # user.save()
        # 注：上诉两种方法添加数据到数据库，用户的密码未被加密

        # create_user方法会自动加密密码
        user = User.objects.create_user(username=username, password=password, mobile=mobile)

        # 设置Session信息
        # request.session["user_id"] = user.id

        # Django为我们提供了状态保持的方法
        from django.contrib.auth import login
        login(request, user)  # user 已经登录的用户信息

        # 5、响应数据
        return JsonResponse({"code": 0, "errmsg": "ok"})


"""
3、用户登录功能
前端：当用户输入完用户名和密码，点击登录按钮，发送axios请求
后端：
    请求：接受请求数据，验证数据
    业务逻辑：验证用户名和密码是否正确，session
    响应：返回Json数据，0表示成功，400表示失败
    
    路由：post login/
"""
class LoginView(View):

    def post(self, request):

        # 1.接受请求数据：body体中的数据为bytes类型数据
        data = json.loads(request.body.decode())
        username = data.get('username')
        password = data.get('password')
        remembered = data.get('remembered')

        # 2.验证数据
        if not all([username, password]):
            return JsonResponse({"code":400, "errmsg":"参数不全"})

        # 多账号登录，即可以使用用户名和密码登录也可以使用手机号和密码登录
        # 根据判断确定是使用手机号查询还是用户名查询
        if re.match("1[3-9]\d{9}", username):
            User.USERNAME_FIELD = "mobile"
        else:
            User.USERNAME_FIELD = "username"

        # 3.验证用户名和密码是否正确 - 方式一
        # users = User.objects.filter(username=username)  # 根据用户名在数据库中查询用户
        # if users.exists():  # 判断Queryset中是否存在数据
        #     # 查询到数据
        #     user = users.first()
        #     if user.password == password:
        #         # 4. session，登录保存状态
        #         from django.contrib.auth import login
        #         login(request, user)  # 用户登录
        #         return JsonResponse({"code": 0, "errmsg":"ok"})
        #     else:
        #         return JsonResponse({"code": 400, "errmsg": "用户名或密码错误"})
        # else:  # 未查询到数据
        #     return JsonResponse({"code": 400, "errmsg": "用户名不存在"})

        # 3.验证用户名和密码是否正确 - 方式二
        from django.contrib.auth import authenticate
        # Django自带用户名和密码验证
        # 如果用户名和密码正确，返回User对象
        # 如果用户名和密码错误，则返回None
        user = authenticate(username=username, password=password)
        if user is None:
            return JsonResponse({"code": 400, "errmsg": "用户名或密码错误"})

        # 4.登录保持状态，session
        from django.contrib.auth import login
        login(request, user)

        # 5.判断是否记住登录
        if remembered:
            # 记住登录，即保存session的过期时间，None表示默认两周
            request.session.set_expiry(None)
        else:
            # 不记住登录，即浏览器关闭session失效
            request.session.set_expiry(0)

        # 6.返回响应
        response = JsonResponse({"code": 0, "errmsg": "ok"})

        # 设置Cookie信息，用户登录后显示用户名
        response.set_cookie("username", username)

        return response


"""
4、用户退出功能
前端：当用户点击退出按钮时，发送axios请求
后端：
    请求：
    业务逻辑：
        1.Django自带的退出功能：django.contrib.auth.logout(request)
        2.删除cookie信息
    响应：

    路由：delete logout/
"""
class LogoutView(View):

    def delete(self, request):
        from django.contrib.auth import logout
        logout(request)  # 退出登录操作，删除Session信息

        # 删除Cookie信息
        response = JsonResponse({"code":0, "errmsg":"ok"})
        response.delete_cookie("username")

        return response


"""
5、用户未登录时访问用户中心
默认情况：未登录时，Django系统返回是的重定向，我们期望返回Json数据，因为前后端是通过Json交互
路由：center/ GET
"""
from utils.views import LoginRequiredJsonMixin
class CenterView(LoginRequiredJsonMixin, View):
    def get(self, request):

        return JsonResponse({"code":0, "errmsg":"ok"})

